﻿using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Tools.Ribbon;
using _Application = Microsoft.Office.Interop.Word._Application;
using Shape = Microsoft.Office.Interop.PowerPoint.Shape;
using Word = Microsoft.Office.Interop.Word;

namespace CreateHandouts {
    public partial class CreateHandouts {
        private void CreateHeandouts_Load(object sender, RibbonUIEventArgs e) {

        }

        private void CreateHandoutsButton_Click(object sender, RibbonControlEventArgs e) {
            if (Globals.ThisAddIn.Application.Presentations.Count != 0) {
                Presentation presentation = Globals.ThisAddIn.Application.ActivePresentation;
                string docname = Path.GetFileNameWithoutExtension(presentation.FullName);
                string scaleText = ScaleEditBox.Text.Replace("%", string.Empty);
                string emptyParagraphsText = emptyParagraphsEditBox.Text;

                int scale;
                int ep;

                int.TryParse(scaleText, out scale);
                int.TryParse(emptyParagraphsText, out ep);
                if (scale == 0) scale = 63;

                CreateWordDoc(presentation.Slides, docname, scale, ep);
            }
        }

        private void CreateWordDoc(Slides slides, string docname, int scale, int emptyParagraphs) {
            // spacer between slide and notes
            int ep = emptyParagraphs;

            try {
                // Create the progress form
                ProgressForm progressForm = new ProgressForm(slides.Count);

                // Create a new thread on the thread pool for the progress form (needed for message looping)
                Thread thread = new Thread(() => System.Windows.Forms.Application.Run(progressForm));
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();

                // Represents the sole instance of the Missing class.
                object missingValue = Missing.Value;
                object endOfDocument = "\\endofdoc"; // '\\endofdoc' is a predefined bookmark representing the end of a Word document

                // launch Word and create a new document.
                _Application wordApplication = new Word.Application { Visible = false };
                _Document wordDocument = wordApplication.Documents.Add(ref missingValue, ref missingValue, ref missingValue, ref missingValue);

                // loop through each slide
                int countSlides = 0;
                foreach (Slide slide in slides) {
                    countSlides++;
                    // create a new GUID ( = unique file name) and export the current slide as .emf
                    string filename = Path.GetTempPath() + @"\" + Guid.NewGuid() + ".emf";
                    slide.Export(filename, "emf");

                    // insert the just exported .emf
                    object oRng = wordDocument.Bookmarks.get_Item(ref endOfDocument).Range;
                    Paragraph paragraph = wordDocument.Content.Paragraphs.Add(ref oRng);
                    InlineShape inlineShape = wordDocument.InlineShapes.AddPicture(filename, ref missingValue, ref missingValue, ref oRng);

                    // delete the temporary file used for exporting the slide
                    File.Delete(filename);

                    // add a single line border to the slide
                    inlineShape.Borders.OutsideLineStyle = WdLineStyle.wdLineStyleSingle;

                    // scale slide
                    if (scale != 63) {
                        inlineShape.ScaleHeight = scale;
                        inlineShape.ScaleWidth = scale;
                    }

                    // center slide
                    inlineShape.Range.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter;

                    // one or  more empty paragraphs as spacers between slide and notes
                    for (int j = 0; j < ep; j++) {
                        oRng = wordDocument.Bookmarks.get_Item(ref endOfDocument).Range;
                        paragraph = wordDocument.Content.Paragraphs.Add(ref oRng);
                        paragraph.Range.InsertParagraphAfter();
                    }

                    // get the end of document
                    Range range = wordDocument.Bookmarks.get_Item(ref endOfDocument).Range;

                    foreach (Shape shape in slide.NotesPage.Shapes) {
                        // check for:
                        // 1) the current slide is a Placeholder
                        // 2) the placeholder is of type PlaceholderBody
                        // 3) the TextFrame contains text
                        if (shape.Type == MsoShapeType.msoPlaceholder && shape.PlaceholderFormat.Type == PpPlaceholderType.ppPlaceholderBody && shape.TextFrame.HasText == MsoTriState.msoTrue) {                                                        
                            Clipboard.Clear();
                            shape.TextFrame.TextRange.Copy();
                            //string test = shape.TextFrame.TextRange.Text;
                            // replace any occurrences of "\r\n" with a space character followed by a propper NewLine sequence (or else word chickens out with a COMException 0x800A1066)
                            Regex defaultRegex = new Regex("^(\r\n)+$");
                            MatchCollection matches = defaultRegex.Matches(Clipboard.GetText());

                            if (matches.Count != 0) Clipboard.SetText(" " + Environment.NewLine);
                            range.Paste();
                        }
                    }

                    // as long as this isn't the last slide ...
                    if (countSlides != slides.Count) {
                        // update the progress dialog
                        progressForm.UpdateProgressSlide();

                        // add page break
                        object wdCollapseEnd = WdCollapseDirection.wdCollapseEnd;
                        object wdPageBreak = WdBreakType.wdPageBreak;
                        range.Collapse(ref wdCollapseEnd);
                        range.InsertBreak(ref wdPageBreak);
                        range.Collapse(ref wdCollapseEnd);
                    }
                }

                // close the progress form
                if (progressForm.InvokeRequired) progressForm.Invoke(new MethodInvoker(progressForm.Close)); else progressForm.Close();

                // if !CreateWordCheckBox.Checked display a saving dialog and save Word document as .pdf
                if (!CreateWordCheckBox.Checked) {
                    SaveFileDialog saveFileDialog = new SaveFileDialog {
                        Filter = "pdf |*.pdf",
                        Title = "Save as .pdf...",
                        FileName = docname
                    };

                    // If the file name is not an empty string proceed with saving
                    if (saveFileDialog.ShowDialog() == DialogResult.OK && saveFileDialog.FileName != string.Empty) {
                        // Create a new thread on the thread pool for the saving form (needed for progress bar animation)
                        SavingForm savingForm = new SavingForm();
                        thread = new Thread(() => System.Windows.Forms.Application.Run(savingForm));
                        thread.SetApartmentState(ApartmentState.MTA);
                        thread.Start();
                        wordDocument.ExportAsFixedFormat(saveFileDialog.FileName, WdExportFormat.wdExportFormatPDF);
                        // close the saving form
                        if (savingForm.InvokeRequired) savingForm.Invoke(new MethodInvoker(savingForm.Close)); else savingForm.Close();
                        // open .pdf file
                        if (MessageBox.Show("Open the .pdf?\nYou should have a .pdf viewer installed!", "Open .pdf?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
                            Process process = new Process { StartInfo = { FileName = saveFileDialog.FileName } };
                            process.Start();
                        }
                    }

                    // Quit Word w/o saving
                    wordApplication.Quit(WdSaveOptions.wdDoNotSaveChanges);
                } else wordApplication.Visible = true; // if CreateWordCheckBox.Checked then do not export the file as .pdf but display the Word window containing the new document,
            } catch (Exception exception) {
                MessageBox.Show("Ups! Something went wrong here: :(\n" + exception.Message);
            }
        }

        private void toggleButton1_Click(object sender, RibbonControlEventArgs e) {
            InfoGroup.Visible = InfoGroup.Visible ? false : true;
        }

        private void OpenBrowserButton_Click(object sender, RibbonControlEventArgs e) {
            Process process = new Process { StartInfo = { FileName = "http://createhandouts.codeplex.com/" } };
            process.Start();
        }
    }
}
